// Copyright 2018-2021 JXMaster. All rights reserved.
/*
* @file NameTest.cpp
* @author JXMaster
* @date 2020/2/20
*/
#include <Runtime/LexicalAnalyzer.hpp>
#include "TestCommon.hpp"

namespace Luna
{
	void lexical_test()
	{
        // LexTestSource.luna
		const char source[] = {
			0x6E, 0x61, 0x6D, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x20, 0x4D, 0x79, 0x4D, 0x6F, 0x64, 0x75,
			0x6C, 0x65, 0x0D, 0x0A, 0x7B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x2F, 0x2A, 0x0D, 0x0A, 0x20,
			0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x53, 0x61, 0x6D, 0x70, 0x6C, 0x65, 0x20, 0x4D, 0x75,
			0x6C, 0x74, 0x69, 0x2D, 0x6C, 0x69, 0x6E, 0x65, 0x20, 0x63, 0x6F, 0x6D, 0x6D, 0x65, 0x6E, 0x74,
			0x2E, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x2A, 0x2F, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x73,
			0x74, 0x72, 0x75, 0x63, 0x74, 0x20, 0x54, 0x65, 0x73, 0x74, 0x43, 0x6C, 0x61, 0x73, 0x73, 0x0D,
			0x0A, 0x20, 0x20, 0x20, 0x20, 0x7B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
			0x2F, 0x2F, 0x20, 0x53, 0x61, 0x6D, 0x70, 0x6C, 0x65, 0x20, 0x73, 0x69, 0x6E, 0x67, 0x6C, 0x65,
			0x2D, 0x6C, 0x69, 0x6E, 0x65, 0x20, 0x63, 0x6F, 0x6D, 0x6D, 0x65, 0x6E, 0x74, 0x2E, 0x0D, 0x0A,
			0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5B, 0x70, 0x72, 0x69, 0x76, 0x61, 0x74, 0x65,
			0x5D, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6C, 0x65, 0x74, 0x20, 0x6D,
			0x75, 0x74, 0x20, 0x74, 0x20, 0x3D, 0x20, 0x74, 0x75, 0x70, 0x6C, 0x65, 0x28, 0x31, 0x32, 0x2C,
			0x20, 0x2D, 0x31, 0x32, 0x35, 0x2C, 0x20, 0x2B, 0x32, 0x33, 0x37, 0x2C, 0x20, 0x35, 0x33, 0x5F,
			0x33, 0x39, 0x35, 0x2C, 0x20, 0x30, 0x62, 0x30, 0x30, 0x31, 0x30, 0x5F, 0x31, 0x30, 0x30, 0x30,
			0x2C, 0x20, 0x2B, 0x30, 0x6F, 0x33, 0x37, 0x35, 0x2C, 0x20, 0x2D, 0x30, 0x78, 0x46, 0x5F, 0x46,
			0x5F, 0x32, 0x5F, 0x65, 0x5F, 0x39, 0x5F, 0x63, 0x5F, 0x33, 0x5F, 0x42, 0x2C, 0x20, 0x2F, 0x2F,
			0x20, 0x49, 0x6E, 0x74, 0x65, 0x67, 0x65, 0x72, 0x73, 0x2E, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20,
			0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x33, 0x2E, 0x30, 0x2C, 0x20, 0x2D, 0x31, 0x32,
			0x2E, 0x32, 0x35, 0x2C, 0x20, 0x2B, 0x33, 0x2E, 0x37, 0x35, 0x2C, 0x20, 0x31, 0x2E, 0x32, 0x35,
			0x65, 0x32, 0x2C, 0x20, 0x32, 0x2E, 0x35, 0x65, 0x2B, 0x32, 0x2C, 0x20, 0x2D, 0x31, 0x32, 0x2E,
			0x35, 0x45, 0x2D, 0x31, 0x2C, 0x20, 0x30, 0x78, 0x46, 0x2E, 0x30, 0x70, 0x32, 0x2C, 0x20, 0x2D,
			0x30, 0x78, 0x33, 0x41, 0x2E, 0x32, 0x45, 0x70, 0x2D, 0x31, 0x2C, 0x20, 0x20, 0x20, 0x20, 0x20,
			0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x2F, 0x2F, 0x20, 0x46, 0x6C, 0x6F, 0x61, 0x74, 0x69,
			0x6E, 0x67, 0x2D, 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x20, 0x6C, 0x69, 0x74, 0x65, 0x72, 0x61, 0x6C,
			0x73, 0x2E, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
			0x27, 0x61, 0x27, 0x2C, 0x20, 0x27, 0xE6, 0x88, 0x91, 0x27, 0x2C, 0x20, 0x27, 0xE3, 0x83, 0xA9,
			0x27, 0x2C, 0x20, 0x27, 0x5C, 0x30, 0x27, 0x2C, 0x20, 0x27, 0x5C, 0x5C, 0x27, 0x2C, 0x20, 0x27,
			0x5C, 0x74, 0x27, 0x2C, 0x20, 0x27, 0x5C, 0x6E, 0x27, 0x2C, 0x20, 0x27, 0x5C, 0x72, 0x27, 0x2C,
			0x20, 0x27, 0x5C, 0x22, 0x27, 0x2C, 0x20, 0x27, 0x5C, 0x27, 0x27, 0x2C, 0x20, 0x27, 0x5C, 0x75,
			0x7B, 0x30, 0x30, 0x39, 0x30, 0x7D, 0x27, 0x2C, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
			0x20, 0x2F, 0x2F, 0x20, 0x43, 0x68, 0x61, 0x72, 0x61, 0x63, 0x74, 0x65, 0x72, 0x20, 0x6C, 0x69,
			0x74, 0x65, 0x72, 0x61, 0x6C, 0x73, 0x2E, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
			0x20, 0x20, 0x20, 0x20, 0x20, 0x22, 0x32, 0x30, 0x32, 0x31, 0x2F, 0x34, 0x2F, 0x32, 0x32, 0x2E,
			0x5C, 0x6E, 0x20, 0xE8, 0xBE, 0x9B, 0xE4, 0xB8, 0x91, 0xE5, 0xB9, 0xB4, 0xE4, 0xB8, 0x89, 0xE6,
			0x9C, 0x88, 0xE5, 0x8D, 0x81, 0xE4, 0xB8, 0x80, 0xE3, 0x80, 0x82, 0x22, 0x2C, 0x0D, 0x0A, 0x20,
			0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2C,
			0x20, 0x66, 0x61, 0x6C, 0x73, 0x65, 0x2C, 0x20, 0x28, 0x75, 0x38, 0x26, 0x3F, 0x29, 0x6E, 0x75,
			0x6C, 0x6C, 0x29, 0x3B, 0x0D, 0x0A, 0x20, 0x20, 0x20, 0x20, 0x7D, 0x0D, 0x0A, 0x7D, 0x00
		};
        LexicalAnalyzer* analyzer = new_lexical_analyzer();
		lexical_analyzer_set_source_string(analyzer, source);
        auto r = lexical_analyzer_run(analyzer);
        if (!r.valid())
        {
            auto& str = lexical_analyzer_get_error_message(analyzer);
            printf("%s\n", str.c_str());
            lutest(false);
        }
		auto& tokens = r.get();
        // Compare the tokens with predefined tokens.
        Vector<LexemeToken> test_tokens = {
            LexemeToken(LexemeTokenType::identifier, "namespace"),
            LexemeToken(LexemeTokenType::identifier, "MyModule"),
            LexemeToken('{'),
            LexemeToken(LexemeTokenType::identifier, "struct"),
            LexemeToken(LexemeTokenType::identifier, "TestClass"),
            LexemeToken('{'),
            LexemeToken('['),
            LexemeToken(LexemeTokenType::identifier, "private"),
            LexemeToken(']'),
            LexemeToken(LexemeTokenType::identifier, "let"),
            LexemeToken(LexemeTokenType::identifier, "mut"),
            LexemeToken(LexemeTokenType::identifier, "t"),
            LexemeToken('='),
            LexemeToken(LexemeTokenType::identifier, "tuple"),
            LexemeToken('('),
            LexemeToken(12i64),
            LexemeToken(','),
			LexemeToken('-'),
            LexemeToken(125i64),
			LexemeToken(','),
			LexemeToken('+'),
			LexemeToken(237i64),
			LexemeToken(','),
			LexemeToken(53395i64),
			LexemeToken(','),
			LexemeToken(40i64),
			LexemeToken(','),
			LexemeToken('+'),
			LexemeToken(0375i64),
			LexemeToken(','),
			LexemeToken('-'),
			LexemeToken(0xFF2E9C3Bi64),
			LexemeToken(','),
			LexemeToken(3.0),
			LexemeToken(','),
			LexemeToken('-'),
			LexemeToken(12.25),
			LexemeToken(','),
			LexemeToken('+'),
			LexemeToken(3.75),
			LexemeToken(','),
			LexemeToken(125.0),
			LexemeToken(','),
			LexemeToken(250.0),
			LexemeToken(','),
			LexemeToken('-'),
			LexemeToken(1.25),
			LexemeToken(','),
			LexemeToken(60.0),
			LexemeToken(','),
			LexemeToken('-'),
			LexemeToken(29.08984375),
			LexemeToken(','),
			LexemeToken((c32)'a'),
			LexemeToken(','),
			LexemeToken((c32)0x6211),
			LexemeToken(','),
			LexemeToken((c32)0x30E9),
			LexemeToken(','),
			LexemeToken((c32)'\0'),
			LexemeToken(','),
			LexemeToken((c32)'\\'),
			LexemeToken(','),
			LexemeToken((c32)'\t'),
			LexemeToken(','),
			LexemeToken((c32)'\n'),
			LexemeToken(','),
			LexemeToken((c32)'\r'),
			LexemeToken(','),
			LexemeToken((c32)'\"'),
			LexemeToken(','),
			LexemeToken((c32)'\''),
			LexemeToken(','),
			LexemeToken((c32)0x0090),
			LexemeToken(','),
			LexemeToken(LexemeTokenType::string_literal, 
				String({'2', '0', '2', '1', '/', '4', '/', '2', '2', '.', '\n', ' ',
					(c8)0xe8, (c8)0xbe, (c8)0x9b, 
					(c8)0xe4, (c8)0xb8, (c8)0x91, 
					(c8)0xe5, (c8)0xb9, (c8)0xb4, 
					(c8)0xe4, (c8)0xb8, (c8)0x89,
					(c8)0xe6, (c8)0x9c, (c8)0x88, 
					(c8)0xe5, (c8)0x8d, (c8)0x81, 
					(c8)0xe4, (c8)0xb8, (c8)0x80, 
					(c8)0xe3, (c8)0x80, (c8)0x82,
					})),
			LexemeToken(','),
			LexemeToken(true),
			LexemeToken(','),
			LexemeToken(false),
			LexemeToken(','),
			LexemeToken('('),
			LexemeToken(LexemeTokenType::identifier, "u8"),
			LexemeToken('&'),
			LexemeToken('?'),
			LexemeToken(')'),
			LexemeToken(),
			LexemeToken(')'),
			LexemeToken(';'),
			LexemeToken('}'),
			LexemeToken('}'),
        };

		lutest(test_tokens.size() == tokens.size());

		for (i32 i = 0; i < tokens.size(); ++i)
		{
			lutest(test_tokens[i].type == tokens[i].type);
			switch (test_tokens[i].type)
			{
			case LexemeTokenType::boolean_literal:
				lutest(test_tokens[i].boolean_literal == tokens[i].boolean_literal); break;
			case LexemeTokenType::character_literal:
				lutest(test_tokens[i].character_literal == tokens[i].character_literal); break;
			case LexemeTokenType::floating_point_literal:
				lutest(test_tokens[i].floating_point_literal == tokens[i].floating_point_literal); break;
			case LexemeTokenType::identifier:
				lutest(!test_tokens[i].identifier.compare(tokens[i].identifier)); break;
			case LexemeTokenType::integer_literal:
				lutest(test_tokens[i].integer_literal == tokens[i].integer_literal); break;
			case LexemeTokenType::null_literal:
				break;
			case LexemeTokenType::string_literal:
				lutest(!test_tokens[i].string_literal.compare(tokens[i].string_literal)); break;
			case LexemeTokenType::symbol:
				lutest(test_tokens[i].symbol == tokens[i].symbol); break;
			}
		}
        delete_lexical_analyzer(analyzer);
	}
}